package TGS;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.util.Date;

import javax.crypto.Cipher;
import javax.crypto.SealedObject;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import tickets.Ticket;
import userdb.UserDb;

public class TGSThread extends Thread {

  private TGS tgs;
  private Socket socket;

  public TGSThread(Socket socket, TGS tgs) {
    super();
    this.tgs = tgs;
    this.socket = socket;
  }

  @Override
  public void run() {

    getTicket();
  }

  private void getTicket() {
    try {
      System.out.println("TGS: Connection established..");
      ObjectInputStream oib = new ObjectInputStream(socket.getInputStream());
      SealedObject tgsTicket = (SealedObject) oib.readObject();
      String partnerName = (String) oib.readObject();
      SealedObject timestamp = (SealedObject) oib.readObject();

      checkTickets(tgsTicket, partnerName, timestamp);
    } catch (IOException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
  }

  private byte[] getKeyab(String name1, String name2) {
    byte[] a1, a2;
    if (name1.compareTo(name2) <= 0) {
      a1 = UserDb.SINGLETON.getUsers().get(name1);
      a2 = UserDb.SINGLETON.getUsers().get(name2);

    } else {
      a1 = UserDb.SINGLETON.getUsers().get(name2);
      a2 = UserDb.SINGLETON.getUsers().get(name1);
    }

    byte[] Kab = new byte[16];

    for (int i = 0; i < 16; i++) {
      if (i % 2 == 0) {
        Kab[i] = a1[i];
      } else {
        Kab[i] = a2[i];
      }
    }
    
    return Kab;
  }

  private void checkTickets(SealedObject tgsTicket, String partnerName, SealedObject timestamp) {

    try {

      // ticket entpacken
      System.out.println("TGS: tgsTicket wird dechiffriert...");
      Ticket t = (Ticket) tgsTicket.getObject(tgs.getKastgs());
      System.out
          .println("TGS: tgsTicket wurde erfolgreich dechiffriert. Name aus dem Ticket: " + t.getName() + " Zeitstempel: " + t.getTime() + "\n");
      if (new Date().getTime() - t.getTime().getTime() > 100000) {// 28800000 8 Stunden Ticket
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        oos.writeObject("EXPIRED"); // Ticket abgelaufen
        oos.flush();
      } else {
        tgs.getTicketTimestamp().put(t.getName(), t.getTime());
        // Zeitstempel holen
        System.out.println("TGS: timestamp wird dechiffriert...");
        Date time = (Date) timestamp.getObject(t.getKey());
        System.out.println("TGS: timestamp wurde erfolgreich dechiffriert...\n");

        Date aktuellezeit = new Date();
        System.out.println("TGS: Aktuelle Zeit auf dem TGS: " + aktuellezeit.toString() + " Zeit vom Client: " + time.toString());
        if (aktuellezeit.getTime() - time.getTime() > 1000) {
          // zulange wartezeit... ticket ung�ltig

          System.err.println();
          ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
          oos.writeObject("BADTIME");
          oos.flush();
        } else {

          SecretKey kab = new SecretKeySpec(getKeyab(t.getName(), partnerName), "AES");
          Ticket t1 = new Ticket(partnerName, kab, null);
          Ticket t2 = new Ticket(t.getName(), kab, null);

          // Ka,tgs()
          Cipher c = Cipher.getInstance(t.getKey().getAlgorithm());
          c.init(Cipher.ENCRYPT_MODE, t.getKey());

          // Ka,tgs(B, Ka,b)
          SealedObject katgsTicket = new SealedObject(t1, c);

          SecretKey kbtgs = tgs.getKeygen().generateKey();
          System.out.println("TGS: passwort: UID" + SecretKey.serialVersionUID + " " + kbtgs.getEncoded());

          c = Cipher.getInstance(kbtgs.getAlgorithm());
          c.init(Cipher.ENCRYPT_MODE, kbtgs);
          SealedObject kbtgsTicket = new SealedObject(t2, c);

          if (katgsTicket != null && kbtgsTicket != null) {
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject("OK");
            oos.writeObject(katgsTicket);
            oos.writeObject(kbtgsTicket);
            oos.flush();
          }
        }
      }
      socket.close();

    } catch (InvalidKeyException e) {
      System.err.println("TGS: Ticket konnte nicht dechiffriert werden, falscher Key");
      ObjectOutputStream oos;
      try {
        oos = new ObjectOutputStream(socket.getOutputStream());
        oos.writeObject("NOK");
        oos.flush();
      } catch (IOException e1) {
        System.out.println("TGS: kann, NOK nicht senden");
        e1.printStackTrace();
      }

      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}
